//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:

rilmain.cpp

Abstract:


Notes:


--*/
/*
------------------------------------------------------------------------------
    Revision History
    Date                Author          Activity ID              Activity Headline
    2007-01-08          qinxuetao       CEDB00040729             Porting ril driver for CC/SMS  
    2007-04-17          qinxuetao       WM600002434              Modified rilpm to send command when CmdThread is exit.
    2007-04-28          qinxuetao       WM600003778              Enable PPC to restore state after SIM reset
    2007-06-21          qinxuetao       WM600007125              Change STK and PB init procedure
    2007-06-28          Qinxuetao       WM600006133              Enable RIL supports PM IOCtrls interface 
    2007-07-10          Qinxuetao       WM600004716              Determine incoming call type for RING notification
    2007-08-14          qinxuetao       WM600009403              Modify SIM phonebook query thread(+WIND?)
------------------------------------------------------------------------------
*/

#include "precomp.h"
#include "rilhand.h"
#include <pm.h>
//
// Globals
//
CRilEventLog g_RilLog;
CRITICAL_SECTION g_csClosing;
#ifdef RIL_RADIO_RESILIENCE
extern CRITICAL_SECTION g_csReboot;
#else
HANDLE g_hCriticalErrorEvent; // = NULL;
#endif // ! RIL_RADIO_RESILIENCE
HANDLE g_hDriverPresentEvent; // = NULL;
HANDLE g_hNewDialOrHangupEvent; // = NULL;
#ifdef OEM2_DRIVER
HANDLE g_hCPINNEvent;
#endif

DWORD g_dwReadyState;
DWORD g_dwRegStatus;
DWORD g_dwGPRSRegStatus;

BOOL g_rfExternalCalltypeDetermination = FALSE;
RILCALLTYPECALLBACK g_rlpfExternalCalltypeFunction = NULL;
HINSTANCE g_hCalltypeLib = NULL;

extern RILCALLINFO g_rgfCallStates[RIL_MAX_TRACKED_CALL_ID];

extern RINGINGCALLDATA g_rcdRingingCallData;
// CS required for safe access - see RINGINGCALLDATA definition for details
CRITICAL_SECTION g_csRingingCallData;

extern DIALEDCALLDATA g_rcdDialedCallData;
// CS required for safe access - see DIALEDCALLDATA definition for details
CRITICAL_SECTION g_csDialedCallData;

extern WAITINGCALLDATA g_rcdWaitingCallData;
// No CS required for safe access - see WAITINGCALLDATA definition for details

// Storage for the SIM toolkit Terminal Profile settings
CRilSTKTerminalProfile g_RilSTKTerminalProfile;

#ifdef RIL_LAST_ERROR
DWORD g_dwLastError;            // = 0;
#endif

#if defined(OEM1_DRIVER) || defined(WAVECOM_DRIVER)
HANDLE g_hWavDev;
#endif 

#ifdef RIL_WATSON_REPORT
// Info Cache for Watson reporting
RilInfoCache g_RilInfoCache;
CRITICAL_SECTION g_csRilInfoCache; 
BOOL g_fWatsonCalled;

// In-memory buffer to capture AT Cmd logs for Watson reports.
CRilATCmdLogBuffer g_RilATCmdLogBuffer;

// Unique platform identifier used as a Watson parameter 
const TCHAR* gc_szWatsonDeviceType = TEXT("Generic");

DWORD g_WatsonThreadId = NULL;
#endif

BOOL        g_cphschange = FALSE;
const char *g_pcszCPHS   = NULL;

#ifdef RIL_ENABLE_EONS
EONS      g_eons;
EONSCache g_eonscache;
BOOL      g_eonschange = FALSE;
#endif

DBGPARAM dpCurSettings = 
{ 
    L"RILDrv", 
    {
        L"Error",      L"Info",       L"Trace",      L"Function",
        L"Read",       L"NDIS",       L"NDIS Packets",  L"Undefined",
        L"Undefined",  L"Undefined",  L"Undefined",  L"Undefined",
        L"Undefined",  L"Undefined",  L"Undefined",  L"Undefined" 
    },
    ZONEMASK_ERROR |ZONEMASK_INFO |ZONEMASK_TRACE | ZONEMASK_READ
};


//
// Stubs for unsupported RILDrv_ functions
//
#define UNSUPPORTED(n, m) \
HRESULT n m \
{ \
    FUNCTION_TRACE(n); \
    RETAILMSG(MSG_ON, (TEXT(#n) TEXT("RILDrv : E :  : E_NOTIMPL\r\n"))); \
    return E_NOTIMPL; \
}


UNSUPPORTED(RILDrv_SetDTMFMonitoring, (DWORD, BOOL));
UNSUPPORTED(RILDrv_GetAudioDevices, (DWORD));
UNSUPPORTED(RILDrv_FetchSimToolkitCmd, (DWORD));
UNSUPPORTED(RILDrv_GetCCBSStatus, (DWORD, DWORD));
UNSUPPORTED(RILDrv_ClearCCBSRegistration, (DWORD, DWORD));
UNSUPPORTED(RILDrv_GetSystemTime, (DWORD));
UNSUPPORTED(RILDrv_GetPacketByteCount, (DWORD));
UNSUPPORTED(RILDrv_ResetPacketByteCount, (DWORD));
UNSUPPORTED(RILDrv_SendFlash, (DWORD, RILADDRESS));
UNSUPPORTED(RILDrv_GetRoamingMode, (DWORD));
UNSUPPORTED(RILDrv_SetRoamingMode, (DWORD, DWORD));
UNSUPPORTED(RILDrv_GetPreferredPrivacyMode, (DWORD));
UNSUPPORTED(RILDrv_SetPreferredPrivacyMode, (DWORD, DWORD));
UNSUPPORTED(RILDrv_GetCurrentPrivacyStatus, (DWORD));
UNSUPPORTED(RILDrv_GetCurrentLocationStatus, (DWORD));
UNSUPPORTED(RILDrv_GetCurrentRoamingStatus, (DWORD));
UNSUPPORTED(RILDrv_SendAKey, (DWORD, LPCSTR));
UNSUPPORTED(RILDrv_DataDormant, (DWORD));

//
// DLL entry point
//
BOOL WINAPI DllMain(HANDLE hinstDll, DWORD dwReason, LPVOID lpReserved)
{
    if (DLL_PROCESS_ATTACH == dwReason)
    {
        g_RilLog.Register();
        DEBUGREGISTER((HMODULE) hinstDll);
        RETAILMSG(MSG_ON, (TEXT("RILDrv : t : DllMain : DLL_PROCESS_ATTACH\r\n")));

    }
    else if (DLL_PROCESS_DETACH == dwReason)
    {
        g_RilLog.Unregister();
        RETAILMSG(MSG_ON, (TEXT("RILDrv : t : DllMain : DLL_PROCESS_DETACH\r\n")));
    }
    return TRUE;
}

#ifdef RIL_ALLOW_DRIVER_REMOVAL_TESTING
CRilHandle * g_pDeviceAllowDriverRemovalTesting = NULL;
#define DRIVERCOOKIE_FROM_RILHANDLE(pDevice)    (DWORD)(g_pDeviceAllowDriverRemovalTesting = pDevice)
#define RILHANDLE_FROM_DRIVERCOOKIE(dwData)     (g_pDeviceAllowDriverRemovalTesting)
#else
#define DRIVERCOOKIE_FROM_RILHANDLE(pDevice)    (DWORD)pDevice;
#define RILHANDLE_FROM_DRIVERCOOKIE(dwData)     (CRilHandle*)dwData;
#endif

//
// RIL driver initialization
//
DWORD RIL_Init(DWORD dwInfo)
{
    FUNCTION_TRACE(RIL_Init);
    RETAILMSG(MSG_ON, (TEXT("RILDrv : t : RIL_Init : params: dwInfo = %d\r\n"), dwInfo));

    CRilHandle* pDevice = NULL;
    DWORD dwRet = 0;
#if defined( OEM1_DRIVER) ||defined(WAVECOM_DRIVER)
    HANDLE hThread = NULL;
#endif
  
    // Initialize globals
    InitializeCriticalSection(&g_csClosing);

#ifdef RIL_RADIO_RESILIENCE
    InitializeCriticalSection(&g_csReboot);
    memset(&g_LastResetTime, 0, sizeof(g_LastResetTime));
#else
    g_hCriticalErrorEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (!g_hCriticalErrorEvent)
    {
        goto Error;
    }
#endif // ! RIL_RADIO_RESILIENCE

#ifdef RIL_WATSON_REPORT
    InitializeCriticalSection(&g_csRilInfoCache);    
#endif // RIL_WATSON_REPORT

#if defined(OEM1_GPRS_DEACT)
    InitializeCriticalSection(&g_csGPRSDeactLock);    
#endif // defined(OEM1_GPRS_DEACT) || defined(EMP_DRIVER)

    InitializeCriticalSection(&g_csDeactCringLock);    

    g_hDriverPresentEvent = CreateEvent(NULL, TRUE, FALSE, RILDRIVERPRESENT_EVENT);
    if (!g_hDriverPresentEvent)
    {
        goto Error;
    }

    g_hNewDialOrHangupEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (!g_hNewDialOrHangupEvent)
    {
        goto Error;
    }

#ifdef OEM2_DRIVER
    g_hCPINNEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!g_hCPINNEvent)
    {
        goto Error;
    }
#endif

#ifdef RIL_WATSON_REPORT
    // Initialize the info cache used for watson reporting
    memset(&(g_RilInfoCache), 0, sizeof(g_RilInfoCache));

    // Initialize flag used to prevent multiple Watson reporting of the same problem
    g_fWatsonCalled = FALSE;

    // Initialize the AT Cmd log
    g_RilATCmdLogBuffer.Init(RILATCMDLOGSIZE);
#endif // RIL_WATSON_REPORT

    // Initialize the default Terminal profile settings.
    g_RilSTKTerminalProfile.InitializeDefault();

    // Allocate a device handle
    pDevice = new CRilHandle;
    if (!pDevice || !pDevice->StartInit())
    {
        goto Error;
    }

    dwRet = DRIVERCOOKIE_FROM_RILHANDLE(pDevice);
#if 0
#if defined(OEM1_DRIVER_PM) ||defined(WAVECOM_DRIVER)
    //
    // PM processing
    //
    hThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)RIL_PmProc, pDevice, 0, NULL);
    if (hThread == NULL)
    {
        RETAILMSG(MSG_ON, (TEXT("RIL: Error PM CreateThread() !\r\n")));
    }

    // no need to keep track of it
    CloseHandle(hThread);
#endif // OEM1_DRIVER_PM || WAVECOM_DRIVER
#endif
    // Driver has started successfully, so set
    // the event that says RIL driver is up.
    SetEvent(g_hDriverPresentEvent);
    g_RilLog.LogEvent(RILLOG_ZONE_PRESENCE, RILLOG_EVENT_RADIOPRESENT);

#if defined(OEM1_DRIVER) || defined(WAVECOM_DRIVER)
    // Open Wave driver 
    g_hWavDev = CreateFile(TEXT("WAV1:"),
        GENERIC_READ | GENERIC_WRITE,
        0, NULL,
        OPEN_EXISTING,
        0, NULL);

    if (g_hWavDev == INVALID_HANDLE_VALUE)
    {
        TBD_OUTPUT(TBDCT_INFO, TBDOL_ERROR, TEXT("RIL_Init : failed to open WavDev driver"));
#if !defined(ENFORA_DRIVER) && !defined(WAVECOM_DRIVER)
        goto Error;
#endif
    }
#endif

    DWORD dwEONSEnabled = 0;

#ifdef RIL_ENABLE_EONS
    {
        /* read EONS cache */
        HRESULT hr = g_eonscache.Read();
        if ( FAILED( hr ) )
        {
            RETAILMSG(MSG_ON, (TEXT("RILDrv : E : RIL_Init : error reading EONS cache -- result [0x%08x]\r\n"), hr));
            goto Error;
        }
        g_eonscache.Dump();

        /* mark as enabled */
        dwEONSEnabled = 1;
    }
#endif

    /* indicate if EONS is enabled */
    {
        RETAILMSG(MSG_ON, (TEXT("RILDrv : i : RIL_Init : EONS [%d]\r\n"), (int)dwEONSEnabled));

        HKEY hkey = NULL;
        LONG l = RegOpenKeyEx( RIL_REGISTRY_ROOT, RIL_SECURE_REGISTRY_KEY, 0, 0, &hkey );
        if ( l == ERROR_SUCCESS )
        {
            DWORD dwSize = sizeof(dwEONSEnabled);
            l = RegSetValueEx( hkey, RIL_REGISTRY_VALUE_EONSENABLED, 0, REG_DWORD, (LPBYTE)&dwEONSEnabled, dwSize );
        }
        if ( hkey != NULL )
        {
            RegCloseKey( hkey );
        }
        hkey = NULL;

        if ( l != ERROR_SUCCESS )
        {
            RETAILMSG(MSG_ON, (TEXT("RILDrv : E : RIL_Init : error writing to RIL secure registry location -- result [0x%08x]\r\n"), HRESULT_FROM_WIN32(l)));
            goto Error;
        }
    }

#ifdef WAVECOM_DRIVER
    g_rfExternalCalltypeDetermination = TRUE;
    InitializeCriticalSection(&g_csDialedCallData);
    InitializeCriticalSection(&g_csRingingCallData);
    RETAILMSG(MSG_ON, (TEXT("RILDrv : i : RIL_Init : Calltype Callback registered, dll = NULL, function = NULL.\r\n")));
#else
    //load calltype determination library
    TCHAR tszCalltypeDll[MAXLENGTH_CALLTYPEKEY];
    TCHAR tszCalltypeFunction[MAXLENGTH_CALLTYPEKEY];
    if (!GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRemoteCalltype, TEXT("CalltypeDLL"), tszCalltypeDll, MAXLENGTH_CALLTYPEKEY))
    {
        RETAILMSG(MSG_ON, (TEXT("RILDrv : i : RIL_Init : No Calltype reg key.\r\n")));
    }
    else
    {
        HINSTANCE hCalltypeLib = LoadLibrary(tszCalltypeDll);
        if (!hCalltypeLib)
            RETAILMSG(MSG_ON, (TEXT("RILDrv : E : RIL_Init : Calltype Lib not loaded, err = 0x%08x.\r\n"),GetLastError()));
        else
        {
            if (!GetRegistrySZ(HKEY_LOCAL_MACHINE, g_tszRegKeyRemoteCalltype, TEXT("CalltypeFunction"), tszCalltypeFunction, MAXLENGTH_CALLTYPEKEY))
            {
                RETAILMSG(MSG_ON, (TEXT("RILDrv : E : RIL_Init : No CalltypeFunction in reg key.\r\n")));
                FreeLibrary(hCalltypeLib);
            }
            else
            {        
                RILCALLTYPECALLBACK rctcb = (RILCALLTYPECALLBACK)GetProcAddress(hCalltypeLib,tszCalltypeFunction);
                if (!rctcb)
                {
                    RETAILMSG(MSG_ON, (TEXT("RILDrv : E : RIL_Init : Calltype Lib GetProcAddress failed, err = 0x%08x.\r\n"),GetLastError()));
                    FreeLibrary(hCalltypeLib);
                }
                else
                {
                    g_rfExternalCalltypeDetermination = TRUE;
                    g_rlpfExternalCalltypeFunction = rctcb;
                    g_hCalltypeLib = hCalltypeLib;
                    InitializeCriticalSection(&g_csDialedCallData);
                    InitializeCriticalSection(&g_csRingingCallData);
                    RETAILMSG(MSG_ON, (TEXT("RILDrv : i : RIL_Init : Calltype Callback registered, dll = %s, function = %s.\r\n"),tszCalltypeDll,tszCalltypeFunction));
                }
            }
        }
    }
#endif

    // Initialize global structures
    memset(&g_rcdRingingCallData, 0, sizeof(g_rcdRingingCallData));
    g_rcdRingingCallData.dwCallId = RIL_MAX_TRACKED_CALL_ID;
    
    memset(&g_rcdDialedCallData, 0, sizeof(g_rcdDialedCallData));
    memset(&g_rcdWaitingCallData, 0, sizeof(g_rcdWaitingCallData));

    memset(&g_rgfCallStates, 0, sizeof(g_rgfCallStates));

    RETAILMSG(MSG_ON, (TEXT("RILDrv : t : RIL_Init : Started successfully\r\n")));

    Error:
    if (!dwRet)
    {
        RETAILMSG(MSG_ON, (TEXT("RILDrv : E : RIL_Init : RIL failed to initialize\r\n")));

        g_RilLog.LogEvent(RILLOG_ZONE_ERROR, RILLOG_EVENT_DRVINITFAILED);

        delete pDevice;

        if (g_hDriverPresentEvent)
        {
            (void)CloseHandle(g_hDriverPresentEvent);
            g_hDriverPresentEvent = NULL;
        }
#ifdef OEM2_DRIVER
        if (g_hCPINNEvent)
        {
            (void)CloseHandle(g_hCPINNEvent);
            g_hCPINNEvent = NULL;
        }
#endif // OEM2_DRIVER
#ifdef RIL_RADIO_RESILIENCE
        DeleteCriticalSection(&g_csReboot);
#else
        if (g_hCriticalErrorEvent)
        {
            (void)CloseHandle(g_hCriticalErrorEvent);
            g_hCriticalErrorEvent = NULL;
        }
#endif // ! RIL_RADIO_RESILIENCE
        DeleteCriticalSection(&g_csClosing);
#ifdef RIL_WATSON_REPORT
        DeleteCriticalSection(&g_csRilInfoCache);
#endif // RIL_WATSON_REPORT

#if defined(OEM1_GPRS_DEACT)
    DeleteCriticalSection(&g_csGPRSDeactLock);    
#endif // defined(OEM1_GPRS_DEACT) || defined(EMP_DRIVER)

    DeleteCriticalSection(&g_csDeactCringLock); 
    }

    return dwRet;
}

//
// Driver de-initialization
//
BOOL RIL_Deinit(DWORD dwData)
{
    FUNCTION_TRACE(RIL_Deinit);
    DEBUGCHK(dwData != 0);

    CRilHandle* pDevice = RILHANDLE_FROM_DRIVERCOOKIE(dwData);
    BOOL fRet = FALSE;

    // Driver is going away. Clear event that
    // says RIL driver is up.
    if (g_hDriverPresentEvent)
    {
        ResetEvent(g_hDriverPresentEvent);
        (void)CloseHandle(g_hDriverPresentEvent);
        g_hDriverPresentEvent = NULL;
        g_RilLog.LogEvent(RILLOG_ZONE_PRESENCE, RILLOG_EVENT_RADIOREMOVED);
    }

    if (g_rfExternalCalltypeDetermination)
    {
        g_rfExternalCalltypeDetermination = FALSE;
        g_rlpfExternalCalltypeFunction = NULL;
        if (NULL != g_hCalltypeLib)
            FreeLibrary(g_hCalltypeLib);
        g_hCalltypeLib = NULL;
        DeleteCriticalSection(&g_csRingingCallData);    
        DeleteCriticalSection(&g_csDialedCallData);    
    }


#if defined(OEM1_DRIVER) || defined(WAVECOM_DRIVER)
    // Close the wavedev driver
    if (g_hWavDev)
    {
        CloseHandle(g_hWavDev);
    }
#endif

    if (!pDevice)
    {
        goto Error;
    }
    delete pDevice;
  
#ifdef OEM2_DRIVER
    if (g_hCPINNEvent)
    {
        (void)CloseHandle(g_hCPINNEvent);
        g_hCPINNEvent = NULL;
    }
#endif // OEM2_DRIVER
#ifdef RIL_RADIO_RESILIENCE
    g_cbLastLockCapsSize = 0;
    FreeBlob(g_pLastLockCaps);
    DeleteCriticalSection(&g_csReboot);
#else
    if (g_hCriticalErrorEvent)
    {
        (void)CloseHandle(g_hCriticalErrorEvent);
        g_hCriticalErrorEvent = NULL;
    }
#endif // ! RIL_RADIO_RESILIENCE

#ifdef RIL_WATSON_REPORT
    DeleteCriticalSection(&g_csRilInfoCache);    
#endif // RIL_WATSON_REPORT

#if defined(OEM1_GPRS_DEACT)
    DeleteCriticalSection(&g_csGPRSDeactLock);    
#endif // defined(OEM1_GPRS_DEACT) || defined(EMP_DRIVER)

    DeleteCriticalSection(&g_csDeactCringLock); 

    DeleteCriticalSection(&g_csClosing);
    fRet = TRUE;

    Error:
    return fRet;
}


//
// Open a driver instance
//
DWORD RIL_Open(DWORD dwData, DWORD dwAccess, DWORD dwShareMode)
{
    FUNCTION_TRACE(RIL_Open);
    DEBUGCHK(dwData != 0);

    CRilInstanceHandle* pHandle = NULL;
    CRilHandle* pDevice = RILHANDLE_FROM_DRIVERCOOKIE(dwData);
#ifdef RIL_ALLOW_DRIVER_REMOVAL_TESTING
    if (!g_pDeviceAllowDriverRemovalTesting)
    {
        return 0x4321;
    }
#endif
    DWORD dwRet = 0;

    // Wait until the COM port is initialized
    if (!pDevice /* || !pDevice->WaitForInit(MAX_DRIVERINIT_TIME) */ )
    {
        goto Error;
    }

    pHandle = new CRilInstanceHandle;
    if (!pHandle || !pHandle->Init(pDevice))
    {
        goto Error;
    }

    // Insert new handle into the handle list
    if (!pDevice->AddToList(pHandle))
    {
        goto Error;
    }

    dwRet = (DWORD)pHandle;

    Error:
    if (!dwRet)
    {
        delete pHandle;
    }
    return dwRet;
}


//
// Close a driver instance
//
BOOL RIL_Close(DWORD dwOpenData)
{
    FUNCTION_TRACE(RIL_Close);
    DEBUGCHK(dwOpenData != 0);

#ifdef RIL_ALLOW_DRIVER_REMOVAL_TESTING
    if (dwOpenData == 0x4321 || !g_pDeviceAllowDriverRemovalTesting)
    {
        return TRUE;
    }
#endif
    CRilInstanceHandle* pHandle = (CRilInstanceHandle*)dwOpenData;
    BOOL fRet = FALSE;

    if (!pHandle)
    {
        goto Error;
    }

    {
        SYNCBLOCK(g_csClosing);

        // Make sure no commands refer to this handle
        pHandle->GetCmdList()->Enum(ClearCmdHandle, 0);
    }

    DEBUGCHK(pHandle->GetDevice() != 0);

    // Remove the handle from the handle list
    if (!pHandle->GetDevice()->RemoveFromList(pHandle))
    {
        goto Error;
    }

    delete pHandle;
    fRet = TRUE;

    Error:
    return fRet;
}



//
// Emulate serial read
//
DWORD RIL_Read(DWORD dwOpenData, LPVOID pBuf, DWORD len)
{
#ifdef RIL_ALLOW_DRIVER_REMOVAL_TESTING
    if (g_pDeviceAllowDriverRemovalTesting)
    {
        RIL_Close(dwOpenData);
        RIL_Deinit(1);
        g_pDeviceAllowDriverRemovalTesting = NULL;
    }
#endif
    return 0;
}


//
// Emulate serial write
//
DWORD RIL_Write(DWORD dwOpenData, LPCVOID pBuf, DWORD len)
{
#ifdef RIL_ALLOW_DRIVER_REMOVAL_TESTING
    if (!g_pDeviceAllowDriverRemovalTesting)
    {
        ASSERT(dwOpenData == 0x4321);
        RIL_Init(1);
    }
#endif
    return 0;
}


//
//
//
DWORD RIL_Seek(DWORD dwOpenData, long pos, DWORD type)
{
    return (DWORD)-1;
}


//
// Defines used in the switch below
//
#define CALLDRVAPI_PARAMS(PARAMSTYPE, APICall)              \
    {                                                       \
        PARAMSTYPE##* pParams = (##PARAMSTYPE##*)pBufIn;    \
        if (pBufIn && dwLenIn == sizeof(PARAMSTYPE)) {      \
            *phr = APICall;                                 \
            dwOutUsed = sizeof(HRESULT);                    \
            fRet = TRUE;                                    \
        }                                                   \
    }

#define CALLDRVAPI_VARPARAMS(PARAMSTYPE, APICall)           \
    {                                                       \
        PARAMSTYPE##* pParams = (##PARAMSTYPE##*)pBufIn;    \
        if (pBufIn && dwLenIn >= sizeof(PARAMSTYPE)) {      \
            *phr = APICall;                                 \
            dwOutUsed = sizeof(HRESULT);                    \
            fRet = TRUE;                                    \
        }                                                   \
    }

#define CALLDRVAPI_OPTVARPARAMS(PARAMSTYPE, APICall)        \
    {                                                       \
        PARAMSTYPE##* pParams = (##PARAMSTYPE##*)pBufIn;    \
        if (!pBufIn || dwLenIn >= sizeof(PARAMSTYPE)) {     \
            *phr = APICall;                                 \
            dwOutUsed = sizeof(HRESULT);                    \
            fRet = TRUE;                                    \
        }                                                   \
    }

#define CALLDRVAPI_ARRAY(ELEMTYPE, APICall)                 \
    {                                                       \
        ELEMTYPE##* pParams = (##ELEMTYPE##*)pBufIn;        \
        if (pBufIn) {                                       \
            *phr = APICall;                                 \
            dwOutUsed = sizeof(HRESULT);                    \
            fRet = TRUE;                                    \
        }                                                   \
    }

#define CALLDRVAPI(APIName)                                 \
    *phr = APIName(dwOpenData);                             \
    dwOutUsed = sizeof(HRESULT);                            \
    fRet = TRUE;


//
//
//
BOOL RIL_IOControl(DWORD dwOpenData, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut,
                   PDWORD pdwActualOut)
{
    FUNCTION_TRACE(RIL_IOControl);
    DEBUGCHK(dwOpenData != 0);

    DWORD dwOutUsed = 0;
    BOOL fRet = FALSE;

    static CEDEVICE_POWER_STATE sRilDx = D0;
    
#ifdef RIL_ALLOW_DRIVER_REMOVAL_TESTING
    if (!g_pDeviceAllowDriverRemovalTesting)
    {
        ASSERT(!"RIL_IOControl should not be called after the driver has gone away");
        return FALSE;
    }
#endif

    CRilInstanceHandle* pHandle = (CRilInstanceHandle*)dwOpenData;
    if (!pHandle)
    {
        goto Error;
    }

    if(SUCCEEDED(ValidateAPIPermission(TEXT("RILGSM"), TEXT("IOControl"), VAP_TRUST_CALLER)))  // Perform security check
    {
        switch (dwCode)
        {
        // CPM is ready for us to register with it
        case IOCTL_RIL_REGISTERWITHCPM:
            {
#ifdef RIL_RADIO_RESILIENCE
                // no longer supported
                fRet = FALSE;
#else
                CRilHandle* pRilDevice = pHandle->GetDevice();
                DEBUGCHK(NULL != pRilDevice);
                fRet = pRilDevice->RegisterWithCPM();
#endif // ! RIL_RADIO_RESILIENCE
            }
            break;

            // This handle will be used for an emergency call - it should be marked as preferred and RIL should be
            //    switched into "emergency mode"
        case IOCTL_RIL_EMERGENCYSTATUS:
            fRet = pHandle->MakePreferred();
            break;

            // Initialize notification delivery
        case IOCTL_RIL_INITNOTIFICATIONS:
            if (pBufIn)
            {
                fRet = pHandle->CreateNotificationQueue((LPCTSTR)pBufIn, pBufOut, dwLenOut, &dwOutUsed);
            }
            break;

            // Get next RIL notification
        case IOCTL_RIL_GETNEXTNOTIFICATION:
            {
                RILDRVNOTIFICATION* pResult = (RILDRVNOTIFICATION*)pBufOut;
                if (pBufOut && dwLenOut >= sizeof(RILDRVNOTIFICATION) &&
                    SUCCEEDED(RILDrv_GetNextNotification(dwOpenData, pResult)))
                {

                    dwOutUsed = pResult->cbSize;
                    fRet = TRUE;
                }
                break;
            }

            // RIL_GetSerialPortStatistics()
        case IOCTL_RIL_GETSERIALPORTSTATISTICS:
            {
                RILSERIALPORTSTATS* pResult = (RILSERIALPORTSTATS*)pBufOut;
                if (pBufOut && dwLenOut >= sizeof(RILSERIALPORTSTATS) &&
                    SUCCEEDED(RILDrv_GetSerialPortStatistics(dwOpenData, pResult)))
                {

                    dwOutUsed = sizeof(RILSERIALPORTSTATS);
                    fRet = TRUE;
                }
                break;
            }

            // RIL_GetDriverVersion()
        case IOCTL_RIL_GETDRIVERVERSION:
            {
                DWORD *pResult = (DWORD *)pBufOut;
                if (pBufOut && dwLenOut >= sizeof(DWORD))
                {
                    // For now, versioning is going to be done manually on an as needed basis
                    *pResult = 0x00020002;
                    dwOutUsed = sizeof(DWORD);
                    fRet = TRUE;
                }
                break;
            }

        case IOCTL_RIL_GETDRIVERVERSIONEX:
            {
            DEFRILVERSIONEX( RilDriverVersionEx );
            const LPRILVERSIONEX pRilDriverVersionExBuf = (LPRILVERSIONEX)pBufOut;
            if ( !pRilDriverVersionExBuf || (dwLenOut < sizeof(RilDriverVersionEx)) )
                {
                RETAILMSG(MSG_ON, (_T("RILDrv : E : RIL_IOControl : IOCTL_RIL_GETDRIVERVERSIONEX : NULL pointer to output buffer or output buffer with insuffcient size [%lu bytes]\r\n"), dwLenOut) );
                break;
                }
            fRet = CeSafeCopyMemory( pRilDriverVersionExBuf, &RilDriverVersionEx, sizeof(RilDriverVersionEx) );
            if ( fRet )
                {
                dwOutUsed = sizeof(RilDriverVersionEx);
                }
            break;
            }

#ifdef RIL_LAST_ERROR
        case IOCTL_RIL_GETLASTERROR:
            {
                DWORD *pResult = (DWORD *)pBufOut;
                if (pBufOut && dwLenOut >= sizeof(DWORD))
                {
                    // Give them back the error
                    *pResult = g_dwLastError;
                    dwOutUsed = sizeof(DWORD);
                    fRet = TRUE;
                }
                break;
            }
            break;
#endif
        case IOCTL_PSL_NOTIFY:
            {
                pHandle->CancelNotifications();
                fRet = TRUE;
                break;
            }

        case IOCTL_RIL_GETSERIALPORTHANDLEFROMCONTEXTID:
            {
                if ( pBufIn && (dwLenIn == sizeof(DWORD)) )
                {
                    if ( SUCCEEDED(RILDrv_GetSerialPortHandleFromContextID(*((DWORD*)pBufIn), (TCHAR*) pBufOut, dwLenOut, &dwOutUsed)))
                    {
                        fRet = TRUE;
                    }
                }
                break;
            }

        case IOCTL_RIL_GETVTSERIALPORTHANDLE:
            {
                if ( SUCCEEDED(RILDrv_GetVTSerialPortHandle((TCHAR*) pBufOut, dwLenOut, &dwOutUsed)))
                {
                    fRet = TRUE;
                }
                break;
            }
        //Power Management IOCtls
        case IOCTL_POWER_CAPABILITIES:  //query supported device power status
            RETAILMSG(MSG_ON, (TEXT("RIL_IOControl: IOCTL_POWER_CAPABILITIES\r\n")));
            if (pBufOut && dwLenOut >= sizeof (POWER_CAPABILITIES)) 
            {
               // __try 
               // {
                    PPOWER_CAPABILITIES pPowerCaps = (PPOWER_CAPABILITIES)pBufOut;
                    memset(pPowerCaps, 0, sizeof(*pPowerCaps));
                    pPowerCaps->DeviceDx = DX_MASK(D0) | DX_MASK(D4);
                    dwOutUsed = sizeof(*pPowerCaps);
                    fRet = TRUE;
               // }
               // __except(EXCEPTION_EXECUTE_HANDLER) 
                //{
                //    RETAILMSG(MSG_ON, (TEXT("exception in IOCTL_POWER_CAPABILITIES\r\n")));
               // }
            }
            break;

        case IOCTL_POWER_QUERY: // determines whether changing power state is feasible
            RETAILMSG(MSG_ON, (TEXT("RIL_IOControl: Received IOCTL_POWER_QUERY\r\n")));
            if (pBufOut && dwLenOut >= sizeof(CEDEVICE_POWER_STATE)) 
            {
                // RIL only supports the transactions  D0->D4 and D4->D0
               // __try 
               // {
                    PCEDEVICE_POWER_STATE pReqDx = (PCEDEVICE_POWER_STATE)pBufOut;
                    RETAILMSG(MSG_ON, (TEXT("IOCTL_POWER_QUERY: D%u\r\n"), *pReqDx));
                    if ( !(*pReqDx == D0 && sRilDx == D4) && 
                         !(*pReqDx == D4 && sRilDx == D0) ) 
                    {
                        // This is a invalid Dx state so return a deny status.
                        *pReqDx = PwrDeviceUnspecified;
                    }
                    dwOutUsed = sizeof(*pReqDx);
                    fRet = TRUE;
                //}
               // __except(EXCEPTION_EXECUTE_HANDLER) 
                //{
                //    RETAILMSG(MSG_ON, (TEXT("exception in IOCTL_POWER_QUERY\r\n")));
               // }
            }
            break;

        case IOCTL_POWER_SET: // requests a change from one device power state to another
            RETAILMSG(MSG_ON, (TEXT("RIL_IOControl: Received IOCTL_POWER_SET\r\n")));
            if (pBufOut && dwLenOut >= sizeof(CEDEVICE_POWER_STATE)) 
            {
                //__try 
               // {
                    PCEDEVICE_POWER_STATE pReqDx = (PCEDEVICE_POWER_STATE)pBufOut;
                    RETAILMSG(MSG_ON, (TEXT("IOCTL_POWER_SET request to D%u \r\n"), *pReqDx));
                    if (VALID_DX(*pReqDx)) 
                    {
                        if(*pReqDx == D0 && sRilDx == D4)
                        {
                            fRet = SUCCEEDED(RILDrv_DisablePowerSavings(dwOpenData));
                        }
                        else if(*pReqDx == D4 && sRilDx == D0)
                        {
                            fRet = SUCCEEDED(RILDrv_EnablePowerSavings(dwOpenData));
                        }
                        if(fRet)
                        {
                            sRilDx = *pReqDx;
                            dwOutUsed = sizeof(*pReqDx);
                        }
                    }
                    else 
                    {
                        RETAILMSG(MSG_ON, (TEXT("Invalid state request D%u\r\n"), *pReqDx));
                    }
                //}
               /// catch(EXCEPTION_EXECUTE_HANDLER) 
               // {
               //     RETAILMSG(MSG_ON, (TEXT("exception in IOCTL_POWER_SET\r\n")));
               // }
            }
            break;

		
        case IOCTL_POWER_GET: // gets the current device power state
            RETAILMSG(MSG_ON, (TEXT("RIL_IOControl: Received IOCTL_POWER_GET\r\n")));
            if (pBufOut && dwLenOut >= sizeof(CEDEVICE_POWER_STATE)) 
            {
               // __try 
               // {
                    PCEDEVICE_POWER_STATE pReqDx = (PCEDEVICE_POWER_STATE)pBufOut;
                    *pReqDx = sRilDx;  
                    RETAILMSG(MSG_ON, (TEXT("IOCTL_POWER_GET: passing back D%u\r\n"), *pReqDx));  
              //  }
               // __except(EXCEPTION_EXECUTE_HANDLER) 
              //  {
              //      RETAILMSG(MSG_ON, (TEXT("exception in IOCTL_POWER_GET\r\n")));
              //  }
            }
            break;
 
        // Other RIL_ APIs
        default:
            {
                HRESULT* phr = (HRESULT*)pBufOut;
                if (!pBufOut || dwLenOut < sizeof(HRESULT))
                {
                    goto Error;
                }

                switch (dwCode)
                {
#ifdef OEM1_DRIVER_PM
                // RIL saving power management io control
                case IOCTL_RIL_POWERSUSPEND:
                    CALLDRVAPI(RILDrv_EnablePowerSavings);
                    break;

                // RIL disable saving power management io control
                case IOCTL_RIL_POWERRESUME:
                    CALLDRVAPI(RILDrv_DisablePowerSavings);
                    break;
#endif  // OEM1_DRIVER_PM
                // RIL_GetSubscriberNumbers()
                case IOCTL_RIL_GETSUBSCRIBERNUMBERS:
                    CALLDRVAPI(RILDrv_GetSubscriberNumbers);
                    break;

                    // RIL_GetOperatorList()
                case IOCTL_RIL_GETOPERATORLIST:
                    CALLDRVAPI(RILDrv_GetOperatorList);
                    break;

                    // RIL_GetPreferredOperatorList()
                case IOCTL_RIL_GETPREFERREDOPERATORLIST:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_GetPreferredOperatorList(dwOpenData, *pParams));
                    break;

                    // RIL_AddPreferredOperator()
                case IOCTL_RIL_ADDPREFERREDOPERATOR:
                    CALLDRVAPI_PARAMS(ADDPREFERREDOPERATOR_PARAMS, RILDrv_AddPreferredOperator(dwOpenData, \
                                                                                                            pParams->dwIndex, &pParams->ronOperatorNames));
                    break;

                    // RIL_RemovePreferredOperator()
                case IOCTL_RIL_REMOVEPREFERREDOPERATOR:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_RemovePreferredOperator(dwOpenData, *pParams));
                    break;

                    // RIL_GetCurrentOperator()
                case IOCTL_RIL_GETCURRENTOPERATOR:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_GetCurrentOperator(dwOpenData, *pParams));
                    break;

                    // RIL_GetAllOperatorsList()
                case IOCTL_RIL_GETALLOPERATORSLIST:
                    CALLDRVAPI(RILDrv_GetAllOperatorsList);
                    break;

                    // RIL_RegisterOnNetwork()
                case IOCTL_RIL_REGISTERONNETWORK:
                    CALLDRVAPI_PARAMS(REGISTERONNETWORK_PARAMS, RILDrv_RegisterOnNetwork(dwOpenData, pParams->dwMode, \
                                                                                                      &pParams->ronOperatorNames));
                    break;

                    // RIL_UnregisterFromNetwork()
                case IOCTL_RIL_UNREGISTERFROMNETWORK:
                    CALLDRVAPI(RILDrv_UnregisterFromNetwork);
                    break;

                    // RIL_GetRegistrationStatus()
                case IOCTL_RIL_GETREGISTRATIONSTATUS:
                    CALLDRVAPI(RILDrv_GetRegistrationStatus);
                    break;

                    // RIL_GetCallerIdSettings()
                case IOCTL_RIL_GETCALLERIDSETTINGS:
                    CALLDRVAPI(RILDrv_GetCallerIdSettings);
                    break;

                    // RIL_SetCallerIdStatus()
                case IOCTL_RIL_SETCALLERIDSTATUS:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetCallerIdStatus(dwOpenData, *pParams));
                    break;

                    // RIL_GetHideIdSettings()
                case IOCTL_RIL_GETHIDEIDSETTINGS:
                    CALLDRVAPI(RILDrv_GetHideIdSettings);
                    break;

                    // RIL_SetHideIdStatus()
                case IOCTL_RIL_SETHIDEIDSTATUS:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetHideIdStatus(dwOpenData, *pParams));
                    break;

                    // RIL_GetDialedIdSettings()
                case IOCTL_RIL_GETDIALEDIDSETTINGS:
                    CALLDRVAPI(RILDrv_GetDialedIdSettings);
                    break;

                    // RIL_SetDialedIdStatus()
                case IOCTL_RIL_SETDIALEDIDSTATUS:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetDialedIdStatus(dwOpenData, *pParams));
                    break;

                    // RIL_GetHideConnectedIdSettings()
                case IOCTL_RIL_GETHIDECONNECTEDIDSETTINGS:
                    CALLDRVAPI(RILDrv_GetHideConnectedIdSettings);
                    break;

                    // RIL_SetHideConnectedIdStatus()
                case IOCTL_RIL_SETHIDECONNECTEDIDSTATUS:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetHideConnectedIdStatus(dwOpenData, *pParams));
                    break;

                    // RIL_GetClosedGroupSettings()
                case IOCTL_RIL_GETCLOSEDGROUPSETTINGS:
                    CALLDRVAPI(RILDrv_GetClosedGroupSettings);
                    break;

                    // RIL_SetClosedGroupSettings()
                case IOCTL_RIL_SETCLOSEDGROUPSETTINGS:
                    CALLDRVAPI_PARAMS(RILCLOSEDGROUPSETTINGS, RILDrv_SetClosedGroupSettings(dwOpenData, pParams));
                    break;

                    // RIL_GetCallForwardingSettings()
                case IOCTL_RIL_GETCALLFORWARDINGSETTINGS:
                    CALLDRVAPI_PARAMS(GETCALLFORWARDING_PARAMS, RILDrv_GetCallForwardingSettings(dwOpenData, pParams->dwReason, pParams->dwInfoClasses));
                    break;

                    // RIL_AddCallForwarding()
                case IOCTL_RIL_ADDCALLFORWARDING:
                    CALLDRVAPI_PARAMS(ADDCALLFORWARDING_PARAMS, RILDrv_AddCallForwarding(dwOpenData, pParams->dwReason, \
                                                                                                      &pParams->rcfsSettings));
                    break;

                    // RIL_RemoveCallForwarding()
                case IOCTL_RIL_REMOVECALLFORWARDING:
                    CALLDRVAPI_PARAMS(REMOVECALLFORWARDING_PARAMS, RILDrv_RemoveCallForwarding(dwOpenData, \
                                                                                                            pParams->dwReason, pParams->dwInfoClasses));
                    break;

                    // RIL_SetCallForwardingStatus()
                case IOCTL_RIL_SETCALLFORWARDINGSTATUS:
                    CALLDRVAPI_PARAMS(SETCALLFORWARDINGSTATUS_PARAMS, RILDrv_SetCallForwardingStatus(dwOpenData, \
                                                                                                     pParams->dwReason, \
                                                                                                     pParams->dwInfoClasses, \
                                                                                                     pParams->dwStatus));
                    break;

                    // RIL_GetCallWaitingSettings()
                case IOCTL_RIL_GETCALLWAITINGSETTINGS:
                    CALLDRVAPI_PARAMS(GETCALLWAITINGSTATUS_PARAMS, RILDrv_GetCallWaitingSettings(dwOpenData, pParams->dwInfoClasses));
                    break;

                    // RIL_SetCallWaitingStatus()
                case IOCTL_RIL_SETCALLWAITINGSTATUS:
                    CALLDRVAPI_PARAMS(SETCALLWAITINGSTATUS_PARAMS, RILDrv_SetCallWaitingStatus(dwOpenData, \
                                                                                                            pParams->dwInfoClasses, pParams->dwStatus));
                    break;

                    // RIL_SendSupServiceData()
                case IOCTL_RIL_SENDSUPSERVICEDATA:
                    CALLDRVAPI_ARRAY(BYTE, RILDrv_SendSupServiceData(dwOpenData, pParams, dwLenIn));
                    break;

                    // RIL_CancelSupServiceDataSession()
                case IOCTL_RIL_CANCELSUPSERVICEDATASESSION:
                    CALLDRVAPI(RILDrv_CancelSupServiceDataSession);
                    break;

                    // RIL_GetCurrentAddressId()
                case IOCTL_RIL_GETCURRENTADDRESSID:
                    CALLDRVAPI(RILDrv_GetCurrentAddressId);
                    break;

                    // RIL_SetCurrentAddressId()
                case IOCTL_RIL_SETCURRENTADDRESSID:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetCurrentAddressId(dwOpenData, *pParams));
                    break;

                    // RIL_Dial()
                case IOCTL_RIL_DIAL:
                    CALLDRVAPI_PARAMS(DIAL_PARAMS, RILDrv_Dial(dwOpenData, pParams->szAddress, pParams->dwType, \
                                                                            pParams->dwOptions));
                    break;

                    // RIL_Asnwer()
                case IOCTL_RIL_ANSWER:
                    CALLDRVAPI(RILDrv_Answer);
                    break;

                    // RIL_Hangup()
                case IOCTL_RIL_HANGUP:
                    CALLDRVAPI(RILDrv_Hangup);
                    break;

                    // RIL_SendDTMF()
                case IOCTL_RIL_SENDDTMF:
                    CALLDRVAPI_ARRAY(SENDDTMF_PARAMS, RILDrv_SendDTMF(dwOpenData, pParams->szDTMF, pParams->dwDuration));
                    break;

                    // RIL_SetDTMFMonitoring()
                case IOCTL_RIL_SETDTMFMONITORING:
                    CALLDRVAPI_PARAMS(BOOL, RILDrv_SetDTMFMonitoring(dwOpenData, *pParams));
                    break;

                    // RIL_GetCallList()
                case IOCTL_RIL_GETCALLLIST:
                    CALLDRVAPI(RILDrv_GetCallList);
                    break;

                    // RIL_ManageCalls()
                case IOCTL_RIL_MANAGECALLS:
                    CALLDRVAPI_PARAMS(MANAGECALLS_PARAMS, RILDrv_ManageCalls(dwOpenData, pParams->dwCommand, pParams->dwID));
                    break;

                    // RIL_TransferCall()
                case IOCTL_RIL_TRANSFERCALL:
                    CALLDRVAPI_PARAMS(TRANSFERCALL_PARAMS, RILDrv_TransferCall(dwOpenData, &pParams->raAddress, \
                                                                                            (pParams->fSubAddress ? &pParams->rsaSubAddress : NULL)));
                    break;

                    // RIL_GetLineStatus()
                case IOCTL_RIL_GETLINESTATUS:
                    CALLDRVAPI(RILDrv_GetLineStatus);
                    break;

                    // RIL_GetAudioGain()
                case IOCTL_RIL_GETAUDIOGAIN:
                    CALLDRVAPI(RILDrv_GetAudioGain);
                    break;

                    // RIL_SetAudioGain()
                case IOCTL_RIL_SETAUDIOGAIN:
                    CALLDRVAPI_PARAMS(RILGAININFO, RILDrv_SetAudioGain(dwOpenData, pParams));
                    break;

                    // RIL_GetAudioDevices()
                case IOCTL_RIL_GETAUDIODEVICES:
                    CALLDRVAPI(RILDrv_GetAudioDevices);
                    break;

                    // RIL_SetAudioDevices()
                case IOCTL_RIL_SETAUDIODEVICES:
                    CALLDRVAPI_PARAMS(RILAUDIODEVICEINFO, RILDrv_SetAudioDevices(dwOpenData, pParams));
                    break;

                    // RIL_GetAudioMuting()
                case IOCTL_RIL_GETAUDIOMUTING:
                    CALLDRVAPI(RILDrv_GetAudioMuting);
                    break;

                    // RIL_SetAudioMuting()
                case IOCTL_RIL_SETAUDIOMUTING:
                    CALLDRVAPI_PARAMS(BOOL, RILDrv_SetAudioMuting(dwOpenData, *pParams));
                    break;

                    // RIL_GetHSCSDOptions()
                case IOCTL_RIL_GETHSCSDOPTIONS:
                    CALLDRVAPI(RILDrv_GetHSCSDOptions);
                    break;

                    // RIL_SetHSCSDOptions()
                case IOCTL_RIL_SETHSCSDOPTIONS:
                    CALLDRVAPI_PARAMS(RILHSCSDINFO, RILDrv_SetHSCSDOptions(dwOpenData, pParams));
                    break;

                    // RIL_GetHSCSDCallSettings()
                case IOCTL_RIL_GETHSCSDCALLSETTINGS:
                    CALLDRVAPI(RILDrv_GetHSCSDCallSettings);
                    break;

                    // RIL_GetDataCompression()
                case IOCTL_RIL_GETDATACOMPRESSION:
                    CALLDRVAPI(RILDrv_GetDataCompression);
                    break;

                    // RIL_SetDataCompression()
                case IOCTL_RIL_SETDATACOMPRESSION:
                    CALLDRVAPI_PARAMS(RILDATACOMPINFO, RILDrv_SetDataCompression(dwOpenData, pParams));
                    break;

                    // RIL_GetErrorCorrection()
                case IOCTL_RIL_GETERRORCORRECTION:
                    CALLDRVAPI(RILDrv_GetErrorCorrection);
                    break;

                    // RIL_SetErrorCorrection()
                case IOCTL_RIL_SETERRORCORRECTION:
                    CALLDRVAPI_PARAMS(RILERRORCORRECTIONINFO, RILDrv_SetErrorCorrection(dwOpenData, pParams));
                    break;

                    // RIL_GetBearerServiceOptions()
                case IOCTL_RIL_GETBEARERSERVICEOPTIONS:
                    CALLDRVAPI(RILDrv_GetBearerServiceOptions);
                    break;

                    // RIL_SetBearerServiceOptions()
                case IOCTL_RIL_SETBEARERSERVICEOPTIONS:
                    CALLDRVAPI_PARAMS(RILBEARERSVCINFO, RILDrv_SetBearerServiceOptions(dwOpenData, pParams));
                    break;

                    // RIL_GetRLPOptions()
                case IOCTL_RIL_GETRLPOPTIONS:
                    CALLDRVAPI(RILDrv_GetRLPOptions);
                    break;

                    // RIL_SetRLPOptions()
                case IOCTL_RIL_SETRLPOPTIONS:
                    CALLDRVAPI_PARAMS(RILRLPINFO, RILDrv_SetRLPOptions(dwOpenData, pParams));
                    break;

                    // RIL_GetMsgServiceOptions()
                case IOCTL_RIL_GETMSGSERVICEOPTIONS:
                    CALLDRVAPI(RILDrv_GetMsgServiceOptions);
                    break;

                    // RIL_SetMsgServiceOptions()
                case IOCTL_RIL_SETMSGSERVICEOPTIONS:
                    CALLDRVAPI_PARAMS(RILMSGSERVICEINFO, RILDrv_SetMsgServiceOptions(dwOpenData, pParams));
                    break;

                    // RIL_GetMsgConfig()
                case IOCTL_RIL_GETMSGCONFIG:
                    CALLDRVAPI(RILDrv_GetMsgConfig);
                    break;

                    // RIL_SetMsgConfig()
                case IOCTL_RIL_SETMSGCONFIG:
                    CALLDRVAPI_PARAMS(RILMSGCONFIG, RILDrv_SetMsgConfig(dwOpenData, pParams));
                    break;

                    // RIL_GetCellBroadcastMsgConfig()
                case IOCTL_RIL_GETCBMSGCONFIG:
                    CALLDRVAPI(RILDrv_GetCellBroadcastMsgConfig);
                    break;

                    // RIL_SetCellBroadcastMsgConfig()
                case IOCTL_RIL_SETCBMSGCONFIG:
                    CALLDRVAPI_OPTVARPARAMS(RILCBMSGCONFIG, RILDrv_SetCellBroadcastMsgConfig(dwOpenData, pParams));
                    break;

                    // RIL_ReadMsg()
                case IOCTL_RIL_READMSG:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_ReadMsg(dwOpenData, *pParams));
                    break;

                    // RIL_DeleteMsg()
                case IOCTL_RIL_DELETEMSG:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_DeleteMsg(dwOpenData, *pParams));
                    break;

                    // RIL_WriteMsg()
                case IOCTL_RIL_WRITEMSG:
                    CALLDRVAPI_PARAMS(WRITEMSG_PARAMS, RILDrv_WriteMsg(dwOpenData, &pParams->rmMessage, pParams->dwStatus));
                    break;

                    // RIL_SendMsg()
                case IOCTL_RIL_SENDMSG:
                    CALLDRVAPI_PARAMS(SENDMSG_PARAMS, RILDrv_SendMsg(dwOpenData, &pParams->rmMessage, pParams->dwOptions));
                    break;

                    // RIL_SendStoredMsg()
                case IOCTL_RIL_SENDSTOREDMSG:
                    CALLDRVAPI_PARAMS(SENDSTOREDMSG_PARAMS, RILDrv_SendStoredMsg(dwOpenData, pParams->dwIndex, \
                                                                                              pParams->dwOptions));
                    break;

                    // RIL_SendMsgAcknowledgement()
                case IOCTL_RIL_SENDMSGACKNOWLEDGEMENT:
                    CALLDRVAPI_PARAMS(BOOL, RILDrv_SendMsgAcknowledgement(dwOpenData, *pParams));
                    break;

                    // RIL_GetUserIdentity()
                case IOCTL_RIL_GETUSERIDENTITY:
                    CALLDRVAPI(RILDrv_GetUserIdentity);
                    break;

                    // RIL_GetUserIdentity()
                case IOCTL_RIL_GETPHONELOCKEDSTATE:
                    CALLDRVAPI(RILDrv_GetPhoneLockedState);
                    break;

                    // RIL_UnlockPhone()
                case IOCTL_RIL_UNLOCKPHONE:
                    CALLDRVAPI_PARAMS(UNLOCKPHONE_PARAMS, RILDrv_UnlockPhone(dwOpenData, pParams->szPassword, \
                                                                                          (pParams->fNewPassword ? pParams->szNewPassword : NULL)));
                    break;

                    // RIL_GetLockingStatus()
                case IOCTL_RIL_GETLOCKINGSTATUS:
                    CALLDRVAPI_PARAMS(GETLOCKINGSTATUS_PARAMS, RILDrv_GetLockingStatus(dwOpenData, pParams->dwFacility, \
                                                                                                    (pParams->fPassword ? pParams->szPassword : NULL)));
                    break;

                    // RIL_SetLockingStatus()
                case IOCTL_RIL_SETLOCKINGSTATUS:
                    CALLDRVAPI_PARAMS(SETLOCKINGSTATUS_PARAMS, RILDrv_SetLockingStatus(dwOpenData, pParams->dwFacility, \
                                                                                                    (pParams->fPassword ? pParams->szPassword: NULL), pParams->dwStatus));
                    break;

                    // RIL_ChangeLockingPassword()
                case IOCTL_RIL_CHANGELOCKINGPASSWORD:
                    CALLDRVAPI_PARAMS(CHANGELOCKINGPASSWORD_PARAMS, RILDrv_ChangeLockingPassword(dwOpenData, \
                                                                                                              pParams->dwFacility, pParams->dwOldPasswordType, pParams->szOldPassword, pParams->szNewPassword));
                    break;

                    // RIL_GetCallBarringStatus()
                case IOCTL_RIL_GETCALLBARRINGSTATUS:
                    CALLDRVAPI_PARAMS(GETCALLBARRINGSTATUS_PARAMS, RILDrv_GetCallBarringStatus(dwOpenData, \
                                                                                                            pParams->dwType, pParams->dwInfoClass, (pParams->fPassword ? pParams->szPassword : NULL)));
                    break;

                    // RIL_SetCallBarringStatus()
                case IOCTL_RIL_SETCALLBARRINGSTATUS:
                    CALLDRVAPI_PARAMS(SETCALLBARRINGSTATUS_PARAMS, RILDrv_SetCallBarringStatus(dwOpenData, \
                                                                                                            pParams->dwType, pParams->dwInfoClass, (pParams->fPassword ? pParams->szPassword : NULL), pParams->dwStatus));
                    break;

                    // RIL_ChangeCallBarringPassword()
                case IOCTL_RIL_CHANGECALLBARRINGPASSWORD:
                    CALLDRVAPI_PARAMS(CHANGECALLBARRINGPASSWORD_PARAMS, RILDrv_ChangeCallBarringPassword(dwOpenData, \
                                                                                                                      pParams->dwType, pParams->szOldPassword, pParams->szNewPassword));
                    break;

                    // RIL_GetEquipmentInfo()
                case IOCTL_RIL_GETEQUIPMENTINFO:
                    CALLDRVAPI(RILDrv_GetEquipmentInfo);
                    break;

                    // RIL_GetEquipmentState()
                case IOCTL_RIL_GETEQUIPMENTSTATE:
                    CALLDRVAPI(RILDrv_GetEquipmentState);
                    break;

                    // RIL_SetEquipmentState()
                case IOCTL_RIL_SETEQUIPMENTSTATE:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetEquipmentState(dwOpenData, *pParams));
                    break;

                    // RIL_GetPhonebookOptions()
                case IOCTL_RIL_GETPHONEBOOKOPTIONS:
                    CALLDRVAPI(RILDrv_GetPhonebookOptions);
                    break;

                    // RIL_SetPhonebookOptions()
                case IOCTL_RIL_SETPHONEBOOKOPTIONS:
                    CALLDRVAPI_PARAMS(RILPHONEBOOKINFO, RILDrv_SetPhonebookOptions(dwOpenData, pParams));
                    break;

                    // RIL_ReadPhonebookEntries()
                case IOCTL_RIL_READPHONEBOOKENTRIES:
                    CALLDRVAPI_PARAMS(READPHONEBOOKENTRIES_PARAMS, RILDrv_ReadPhonebookEntries(dwOpenData, \
                                                                                                            pParams->dwStartIndex, pParams->dwEndIndex));
                    break;

                    // RIL_WritePhonebookEntry()
                case IOCTL_RIL_WRITEPHONEBOOKENTRY:
                    CALLDRVAPI_PARAMS(RILPHONEBOOKENTRY, RILDrv_WritePhonebookEntry(dwOpenData, pParams));
                    break;

                    // RIL_DeletePhonebookEntry()
                case IOCTL_RIL_DELETEPHONEBOOKENTRY:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_DeletePhonebookEntry(dwOpenData, *pParams));
                    break;

                    // RIL_SendSimCmd()
                case IOCTL_RIL_SENDSIMCMD:
                    CALLDRVAPI_ARRAY(BYTE, RILDrv_SendSimCmd(dwOpenData, pParams, dwLenIn));
                    break;

                    // RIL_SendRestrictedSimCmd()
                case IOCTL_RIL_SENDRESTRICTEDSIMCMD:
                    CALLDRVAPI_ARRAY(SENDRESTRICTEDSIMCMD_PARAMS, RILDrv_SendRestrictedSimCmd(dwOpenData, \
                                                                                                           pParams->dwCommand, &pParams->rscpParameters, pParams->pbData, \
                                                                                                           dwLenIn - sizeof(SENDRESTRICTEDSIMCMD_PARAMS)));
                    break;

                    // RIL_GetSimRecordStatus()
                case IOCTL_RIL_GETSIMRECORDSTATUS:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_GetSimRecordStatus(dwOpenData, *pParams));
                    break;

                    // RIL_GetSimToolkitProfile()
                case IOCTL_RIL_GETSIMTOOLKITPROFILE:
                    CALLDRVAPI(RILDrv_GetSimToolkitProfile);
                    break;

                    // RIL_SetSimToolkitProfile()
                case IOCTL_RIL_SETSIMTOOLKITPROFILE:
                    CALLDRVAPI_ARRAY(BYTE, RILDrv_SetSimToolkitProfile(dwOpenData, pParams, dwLenIn));
                    break;

                    // RIL_SendSimToolkitEnvelopeCmd()
                case IOCTL_RIL_SENDSIMTOOLKITENVELOPECMD:
                    CALLDRVAPI_ARRAY(BYTE, RILDrv_SendSimToolkitEnvelopeCmd(dwOpenData, pParams, dwLenIn));
                    break;

                    // RIL_FetchSimToolkitCmd()
                case IOCTL_RIL_FETCHSIMTOOLKITCMD:
                    CALLDRVAPI(RILDrv_FetchSimToolkitCmd);
                    break;

                    // RIL_SendSimToolkitCmdResponse()
                case IOCTL_RIL_SENDSIMTOOLKITCMDRESPONSE:
                    CALLDRVAPI_ARRAY(SENDSIMTOOLKITCMDRESPONSE_PARAMS, RILDrv_SendSimToolkitCmdResponse(dwOpenData,           \
                                                                                                         &pParams->rstrRsp,   \
                                                                                                         pParams->pbDetails,  \
                                                                                                         dwLenIn - sizeof(SENDSIMTOOLKITCMDRESPONSE_PARAMS)));
                    break;

                    // RIL_TerminateSimToolkitSession()
                case IOCTL_RIL_TERMINATESIMTOOLKITSESSION:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_TerminateSimToolkitSession(dwOpenData, *pParams));
                    break;

                    // RIL_SendSimToolkitEventDownload()
                case IOCTL_RIL_SENDSIMTOOLKITEVENTDOWNLOAD:
                    CALLDRVAPI_ARRAY(SENDSIMTOOLKITEVENTDOWNLOAD_PARAMS, RILDrv_SendSimToolkitEventDownload(dwOpenData,       \
                                                                                                            pParams->dwEvent, \
                                                                                                            pParams->pbData,  \
                                                                                                            dwLenIn - sizeof(SENDSIMTOOLKITEVENTDOWNLOAD_PARAMS)));
                    break;

                    // RIL_GetCostInfo()
                case IOCTL_RIL_GETCOSTINFO:
                    CALLDRVAPI(RILDrv_GetCostInfo);
                    break;

                    // RIL_SetCostInfo()
                case IOCTL_RIL_SETCOSTINFO:
                    CALLDRVAPI_PARAMS(SETCOSTINFO_PARAMS, RILDrv_SetCostInfo(dwOpenData, &pParams->rciCostInfo, \
                                                                                          (pParams->fPassword ? pParams->szPassword : NULL)));
                    break;

                    // RIL_GetSignalQuality()
                case IOCTL_RIL_GETSIGNALQUALITY:
                    CALLDRVAPI(RILDrv_GetSignalQuality);
                    break;

                    // RIL_GetCellTowerInfo()
                case IOCTL_RIL_GETCELLTOWERINFO:
                    CALLDRVAPI(RILDrv_GetCellTowerInfo);
                    break;

                    // RIL_DevSpecific()
                case IOCTL_RIL_DEVSPECIFIC:
                    CALLDRVAPI_ARRAY(BYTE, RILDrv_DevSpecific(dwOpenData, pParams, dwLenIn));
                    break;

                    // RIL_GetDevCaps()
                case IOCTL_RIL_GETDEVCAPS:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_GetDevCaps(dwOpenData, *pParams));
                    break;

                    // RIL_GetCCBSStatus()
                case IOCTL_RIL_GETCCBSSTATUS:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_GetCCBSStatus(dwOpenData, *pParams));
                    break;

                    // RIL_ClearCCBSRegistration()
                case IOCTL_RIL_CLEARCCBSREGISTRATION:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_ClearCCBSRegistration(dwOpenData, *pParams));
                    break;
                case IOCTL_RIL_GETSYSTEMTIME:
                    CALLDRVAPI(RILDrv_GetSystemTime);
                    break;
                case IOCTL_RIL_GETGPRSCONTEXTLIST:
                    CALLDRVAPI(RILDrv_GetGPRSContextList);
                    break;
                case IOCTL_RIL_SETGPRSCONTEXT:
                    CALLDRVAPI_VARPARAMS(RILGPRSCONTEXT, RILDrv_SetGPRSContext(dwOpenData, pParams));
                    break;
                case IOCTL_RIL_DELETEGPRSCONTEXT:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_DeleteGPRSContext(dwOpenData, *pParams));
                    break;
                case IOCTL_RIL_GETREQUESTEDQUALITYOFSERVICELIST:
                    CALLDRVAPI(RILDrv_GetRequestedQualityOfServiceList);
                    break;
                case IOCTL_RIL_SETREQUESTEDQUALITYOFSERVICE:
                    CALLDRVAPI_PARAMS(RILGPRSQOSPROFILE, RILDrv_SetRequestedQualityOfService(dwOpenData, pParams));
                    break;
                case IOCTL_RIL_DELETEREQUESTEDQUALITYOFSERVICE:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_DeleteRequestedQualityOfService(dwOpenData, *pParams));
                    break;
                case IOCTL_RIL_GETMINIMUMQUALITYOFSERVICELIST:
                    CALLDRVAPI(RILDrv_GetMinimumQualityOfServiceList);
                    break;
                case IOCTL_RIL_SETMINIMUMQUALITYOFSERVICE:
                    CALLDRVAPI_PARAMS(RILGPRSQOSPROFILE, RILDrv_SetMinimumQualityOfService(dwOpenData, pParams));
                    break;
                case IOCTL_RIL_DELETEMINIMUMQUALITYOFSERVICE:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_DeleteMinimumQualityOfService(dwOpenData, *pParams));
                    break;
                case IOCTL_RIL_SETGPRSATTACHED:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetGPRSAttached(dwOpenData, *pParams));
                    break;
                case IOCTL_RIL_GETGPRSATTACHED:
                    CALLDRVAPI(RILDrv_GetGPRSAttached);
                    break;
                case IOCTL_RIL_SETGPRSCONTEXTACTIVATED:
                    CALLDRVAPI_PARAMS(SETGPRSCONTEXTACTIVATED_PARAMS, RILDrv_SetGPRSContextActivated(dwOpenData, pParams->dwContextID, pParams->fContextActivation));
                    break;
                case IOCTL_RIL_GETGPRSCONTEXTACTIVATEDLIST:
                    CALLDRVAPI(RILDrv_GetGPRSContextActivatedList);
                    break;
                case IOCTL_RIL_ENTERGPRSDATAMODE:
                    CALLDRVAPI_OPTVARPARAMS(RILENTERGPRSDATAMODE, RILDrv_EnterGPRSDataMode(dwOpenData, pParams));
                    break;
                case IOCTL_RIL_GETGPRSADDRESS:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_GetGPRSAddress(dwOpenData, *pParams));
                    break;
                case IOCTL_RIL_GPRSANSWER:
                    CALLDRVAPI_VARPARAMS(RILGPRSANSWER, RILDrv_GPRSAnswer(dwOpenData, pParams));
                    break;
                case IOCTL_RIL_GETGPRSREGISTRATIONSTATUS:
                    CALLDRVAPI(RILDrv_GetGPRSRegistrationStatus);
                    break;
                case IOCTL_RIL_GETGPRSCLASS:
                    CALLDRVAPI(RILDrv_GetGPRSClass);
                    break;
                case IOCTL_RIL_SETGPRSCLASS:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetGPRSClass(dwOpenData, *pParams));
                    break;
                case IOCTL_RIL_GETMOSMSSERVICE:
                    CALLDRVAPI(RILDrv_GetMOSMSService);
                    break;
                case IOCTL_RIL_SETMOSMSSERVICE:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetMOSMSService(dwOpenData, *pParams));
                    break;
                case IOCTL_RIL_NDIS_SETGPRSCONTEXTACTIVATED:
                    CALLDRVAPI_PARAMS(RILNDISGPRSCONTEXT, RILDrv_NdisSetGPRSContextActivated(dwOpenData, pParams));
                    break;

                // CDMA functions
                case IOCTL_RIL_GETPACKETBYTECOUNT:
                    CALLDRVAPI(RILDrv_GetPacketByteCount);
                    break;

                case IOCTL_RIL_RESETPACKETBYTECOUNT:
                    CALLDRVAPI(RILDrv_ResetPacketByteCount);
                    break;

                case IOCTL_RIL_GETCURRENTSYSTEMTYPE:
                    CALLDRVAPI(RILDrv_GetCurrentSystemType);
                    break;

                case IOCTL_RIL_SENDFLASH:
                    CALLDRVAPI_PARAMS(RILADDRESS, RILDrv_SendFlash(dwOpenData, *pParams));
                    break;

                case IOCTL_RIL_GETROAMINGMODE:
                    CALLDRVAPI(RILDrv_GetRoamingMode);
                    break;

                case IOCTL_RIL_SETROAMINGMODE:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetRoamingMode(dwOpenData, *pParams));
                    break;

                case IOCTL_RIL_GETPREFERREDPRIVACYMODE:
                    CALLDRVAPI(RILDrv_GetPreferredPrivacyMode);
                    break;

                case IOCTL_RIL_SETPREFERREDPRIVACYMODE:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetPreferredPrivacyMode(dwOpenData, *pParams));
                    break;

                case IOCTL_RIL_GETCURRENTPRIVACYSTATUS:
                    CALLDRVAPI(RILDrv_GetCurrentPrivacyStatus);
                    break;

                case IOCTL_RIL_GETCURRENTLOCATIONSTATUS:
                    CALLDRVAPI(RILDrv_GetCurrentLocationStatus);
                    break;

                case IOCTL_RIL_GETCURRENTROAMINGSTATUS:
                    CALLDRVAPI(RILDrv_GetCurrentRoamingStatus);
                    break;

                case IOCTL_RIL_SENDAKEY:
                    // parameters to SendAKey are a little wierd, so there isn't a suitable macro yet.
                    *phr = RILDrv_SendAKey(dwOpenData, (LPCSTR)pBufIn);
                    dwOutUsed = sizeof(HRESULT);
                    fRet = TRUE; 
                    break;                    

                case IOCTL_RIL_REGISTER_AT_LOGGING:
                    CALLDRVAPI_PARAMS(DWORD, RILDrv_SetATLogging(dwOpenData, *pParams ));
                    break;

                case IOCTL_RIL_ATCOMMAND_LOGFILE:
                    CALLDRVAPI_ARRAY(TCHAR, RILDrv_ATLogFile(dwOpenData, pParams ));
                    break;

                case IOCTL_RIL_GETATR:
                    CALLDRVAPI(RILDrv_GetATR);
                    break;

                case IOCTL_RIL_LOGEVENTTORADIO:
                    CALLDRVAPI_ARRAY(CHAR, RILDrv_LogEventToRadio(dwOpenData, pParams));
                    break;

                case IOCTL_RIL_DATADORMANT:
                    CALLDRVAPI(RILDrv_DataDormant);
                    break;

                }
                break;
            }
        }
    }

    if (pdwActualOut)
    {
        *pdwActualOut = dwOutUsed;
    }





    Error:
    return fRet;
}


//
//
//
HRESULT RILDrv_GetNextNotification(DWORD dwParam, RILDRVNOTIFICATION* lpRilDrvNotification)
{
    FUNCTION_TRACE(RILDrv_GetNextNotification);
    HRESULT hr = S_OK;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam, TRUE);
    if (!pHandle)
    {
        hr = E_INVALIDARG;
        goto Error;
    }

    if (!pHandle->GetNextNotification(*lpRilDrvNotification))
    {
        hr = E_FAIL;
    }

    Error:
    return hr;
}


//
//
//
HRESULT RILDrv_GetSerialPortStatistics(DWORD dwParam, RILSERIALPORTSTATS* lpSerialPortStats)
{
    FUNCTION_TRACE(RILDrv_GetSerialPortStatistics);
    HRESULT hr = S_OK;
    CRilHandle* pRilDevice;
    CComHandle* pComDevice;
    CRilInstanceHandle* pHandle = ExtractHandle(dwParam);
    if (!pHandle)
    {
        hr = E_INVALIDARG;
        goto Error;
    }

    pRilDevice = pHandle->GetDevice();
    DEBUGCHK(NULL != pRilDevice);

    pComDevice = pRilDevice->GetComDevice();
    DEBUGCHK(NULL != pComDevice);

    pComDevice->CalculateComStats(lpSerialPortStats->dwReadBitsPerSecond, lpSerialPortStats->dwWrittenBitsPerSecond);
    lpSerialPortStats->dwParams = RIL_PARAM_SPS_ALL;

    Error:
    return hr;
}


//
// Function passed to CQueue::Enum() above
//
BOOL ClearCmdHandle(void* pItem, DWORD dwDummy)
{
    FUNCTION_TRACE(ClearCmdHandle);
    DEBUGCHK(pItem != NULL);

    CCommand* pCmd = (CCommand*)pItem;
    pCmd->ClearHandle();

    // Continue enumeration
    return FALSE;
}


//
//
//
CRilInstanceHandle* const ExtractHandle(const DWORD dwParam, BOOL bOverrideEmergency)
{
    FUNCTION_TRACE(ExtractHandle);
    CRilInstanceHandle* pRet;
    CRilHandle* pRilDevice;

    // Cast the DWORD into a handle
    pRet = (CRilInstanceHandle*)dwParam;
    if (!pRet)
    {
        goto Error;
    }

    pRilDevice = pRet->GetDevice();
    DEBUGCHK(NULL != pRilDevice);

    // If we're in emergency mode, make sure this is a preferred handle
    if ((!bOverrideEmergency) && pRilDevice->FInEmergencyMode() && !pRet->FPreferred())
    {
        pRet = NULL;
        goto Error;
    }

    Error:
    return pRet;
}


#ifndef RIL_RADIO_RESILIENCE
DWORD g_SignalCriticalErrorEventId=0;
#endif

//
//
//
void SignalCriticalError(DWORD dwEventId, DWORD dwLineNum, char *lpszFileName)
{
    FUNCTION_TRACE(SignalCriticalError);
    RETAILMSG(MSG_ON, (TEXT("RILDrv : E : SignalCriticalError : dwEventId=%d, dwLineNum=%d, lpszFileName=%hs\r\n"), dwEventId, dwLineNum, lpszFileName));
    g_RilLog.LogEvent(RILLOG_ZONE_ERROR, dwEventId);

#ifdef RIL_WATSON_REPORT    
    // For general reinits, check if the radio has been previously reset before sending
    // another Watson report. We will always receive a re-init to restore the radio state
    // after an explicit radio reset and do not want to duplicate Watson reports.
    if (RILLOG_EVENT_GENERALREINIT == dwEventId)
    {
        if (g_RilInfoCache.fRadioWasReset)
        {
            // Reset the flag, but do not call Watson a second time.
            g_RilInfoCache.fRadioWasReset = FALSE;
        }
        else
        {
            // Check if Watson has been called recently
            if (!g_fWatsonCalled)
            {
                // A general init occurred without a prior explicit radio reset,
                // launch watson to report the error.
                WatsonReport(&g_RilATCmdLogBuffer, &g_RilInfoCache, dwEventId, gc_szWatsonDeviceType);       
                g_RilInfoCache.fRadioWasReset = FALSE;
                g_fWatsonCalled = TRUE;
            }
        }
    }
    // If Watson hasn't been called recently, then for everything else except a low memory error, 
    // send a Watson log. Later on, set a flag if the radio is reset to prevent Watson from being
    // called on the radio re-init.
    else if (!g_fWatsonCalled && (RILLOG_EVENT_LOWMEMORY != dwEventId))
    {
        WatsonReport(&g_RilATCmdLogBuffer, &g_RilInfoCache, dwEventId, gc_szWatsonDeviceType);       
        g_fWatsonCalled = TRUE;
    }
#endif // RIL_WATSON_REPORT

#ifdef RIL_RADIO_RESILIENCE
    BOOL fRadioReset = FALSE;

    switch(dwEventId)
    {
        case RILLOG_EVENT_GENERALREINIT:
            RETAILMSG(MSG_ON, (TEXT("RILDrv : E : SignalCriticalError : Radio reboot detected, restore radio state\r\n")));
            GetSystemTime(&g_LastResetTime);
            g_fRadioResetRecently = TRUE;    
            RebootRestoreState();        
            break;
        case RILLOG_EVENT_GPRSFATALERROR:            
            RETAILMSG(MSG_ON, (TEXT("RILDrv : E : SignalCriticalError : GPRS Fatal error detected, reboot radio\r\n")));
            fRadioReset = RebootRadio();
            break;
        case RILLOG_EVENT_TOOMANYTIMEOUTS:
            RETAILMSG(MSG_ON, (TEXT("RILDrv : E : SignalCriticalError : Too many timeouts detected, reboot radio\r\n")));
            fRadioReset = RebootRadio();
            break;
        default:            
            RETAILMSG(MSG_ON, (TEXT("RILDrv : E : SignalCriticalError : Non fatal error, don't reboot\r\n")));
#ifdef RIL_WATSON_REPORT
            g_RilInfoCache.fRadioWasReset = FALSE;
#endif // RIL_WATSON_REPORT
            break;
    }
#ifdef RIL_WATSON_REPORT
        // The radio was actually reset, set the flag to prevent Watson from being called a second time on the
        // radio re-init.
        if (fRadioReset)
        {
            g_RilInfoCache.fRadioWasReset = TRUE;
        }
    
        if (RILLOG_EVENT_GENERALREINIT == dwEventId)
        {
            // Log last radio reset time to the info cache.
            g_RilInfoCache.stRadioReset = g_LastResetTime;
        }
        else 
        {
            // Log last radio reset time to the info cache.
            GetSystemTime(&g_RilInfoCache.stRadioReset );
        }
#endif // RIL_WATSON_REPORT
    
#else // !RIL_RADIO_RESILIENCE
    
#ifdef RIL_WATSON_REPORT
        // Log last radio reset time to the info cache.
        GetSystemTime(&g_RilInfoCache.stRadioReset );
#endif // RIL_WATSON_REPORT
    g_SignalCriticalErrorEventId=dwEventId;
    (void)SetEvent(g_hCriticalErrorEvent);
#endif // RIL_RADIO_RESILIENCE
}

DWORD RIL_RestoreStateProc(LPVOID lpParameter)
{
    RETAILMSG(MSG_ON, (TEXT("Function: RIL_RestoreStateProc.\r\n")));
    SignalCriticalError(RILLOG_EVENT_GENERALREINIT, __LINE__, __FILE__);
    return S_OK;
}